"""
Welcome to the GeneTrack Project
================================

GeneTrack is a high performance bioinformatics data storage and 
analysis system designed to store genome wide information. 
It is currently used to store and visualize sequencing data obtained 
via large throughput rapid sequencing platforms such as the 454 and Solexa. 

$Rev: 237 $ 
$Author: ialbert $ 
$Date: 2008-02-07 11:13:29 -0500 (Thu, 07 Feb 2008) $
"""

import os, sys, logging, re, gc

def version_check( version=(2,5) ):
    "Verifies the version of python"
    if sys.version_info < version:
        currver = '.'.join(map(str, sys.version_info))
        reqver  = '.'.join(map(str, version))
        sys.stderr.write( "*** This program requires python version %s or higher\n" % reqver)
        sys.stderr.write( "*** Current python version is: %s\n" % currver )
        sys.exit()

version_check()

from atlas import util

from atlas.util import nice_sort, commify

# the maximum size of the vector at least 4 bytes per index 
# i.e. 10 million elements will take at least 40Mb
VECTOR_SIZE = 10**2

class Param(object):
    """
    Generic class that provides attribute access to dictionary data

    >>> param = Param( name='Joe', age=13)
    >>> param.name, param.age
    ('Joe', 13)
    >>> 'name' in param
    True
    >>> param.defaults( dict(test=True) )
    >>> param.test
    True
    >>> param.defaults( dict(test=False) )
    >>> param.test
    True
    >>> param.update( dict(test=False) )
    >>> param.test
    False
    >>> param.keys()
    ['test', 'age', 'name']
    """
    def __init__(self, **kwds ):
        self.__dict__.update( kwds )
    
    def __repr__(self):
        return "%s=%s" % (self.__class__.__name__, self.__dict__)
    
    def __setitem__(self, index, value):
        setattr(self, index, value)

    def __getitem__(self, index):
        getattr(self, index)

    def copy( self ):
        return Param( **self.__dict__ ) 
    
    def __contains__( self, key):
        return key in self.__dict__
    
    def keys(self):
        return self.__dict__.keys()
    
    def items(self):
        return self.__dict__.items()

    def defaults(self, param):
        """
        Updates the parameters with values from dictionary like parameter 
        (needs items() method) only if there are no values for these fields
        """
        for key, value in param.items():
            if key not in self.__dict__:
                self.__dict__[key] = value

    def update(self, param):
        """
        Updates the parameters with the content of the dictionary like parameter
        ( needs items() method ) 
        """
        self.__dict__.update( param.items() )
    
    def get(self, key, default=None):
        """
        Returns the value of the key if exists, default value otherwise
        """
        return self.__dict__.get(key, default)

def join_paths(*args):
    """
    Joins and normalizes a path
    """
    return os.path.abspath( os.path.join(*args) )

def module_import( name ):
    """
    Attempts to import a name

    >>> m = module_import( 'os.path' )
    """
    try:
        mod = __import__( name )
        info('imported %s' % name )
        debug('imported %s from %s' % (name, mod.__file__) )
        components = name.split('.')
        for comp in components[1:]:
            mod = getattr(mod, comp)
            debug('imported %s from %s' % (comp, mod.__file__) )
        return mod

    except ImportError, exc:
        error("  unable to import %s -> %s" % (name, exc) )
        sys.exit()

# sets up a local environment
ENV = Param( verbose=False )

# current directory
__curr_dir = util.getdir( __file__ ) 
ENV.CURR_DIR = join_paths( __curr_dir )
ENV.HOME_DIR = join_paths( ENV.CURR_DIR, '..', 'home'  ) 
ENV.LIBRARY_DIR = join_paths( ENV.CURR_DIR, '..', 'library'  ) 
ENV.TEST_DIR = join_paths( ENV.CURR_DIR, '..', 'tests' )
ENV.TEST_DATA_DIR = join_paths( ENV.TEST_DIR, 'data' )

def get_logger( name='ATLAS', stream=sys.stdout):
    """
    Returns a logger
    >>> log = get_logger()
    >>> # use like so:
    >>> # log.info( 'info level message' )
    >>> # log.error( 'error level message' )
    """
    logger = logging.getLogger(name)
    
    # various details of loggin
    #format = '%(levelname)s %(asctime)-15s %(module)s.%(funcName)s: %(message)s'
    #format = '%(levelname)s %(module)s: %(message)s'
    
    format = '%(levelname)s %(module)s.%(funcName)s: %(message)s'
    
    logging.basicConfig( format=format, level=logging.DEBUG, stream=stream ) 
    return logger

def disable_loglevel( level=0 ):
    """
    Disables logging levels
    """
    level = str(level)
    value = dict( NOTSET=0, DEBUG=10, INFO=20, WARNING=30).get( level.upper(), 0)
    logging.disable( value )

log = get_logger()
info, error, warn, debug = log.info, log.error, log.warn, log.debug

def fatal( msg):
    "An error that will stop execution"
    error( msg )
    sys.exit()

def join( data, sep='\t', patt='%s'):
    """
    >>> join( ['a', 'b', 'c'], sep=', ' )
    'a, b, c'
    >>> join( [1, 2, 3], sep=', ' )
    '1, 2, 3'
    """
    return patt % sep.join( map(str, data) )

def save_pid( homedir='', fname='atlas.pid'):
    """
    Saves the current process id to a file
    """
    file( join_paths( homedir,  fname ), 'wt').write( '%s\n' % os.getpid() )

def isfile( path, verify=True):
    """
    Verifies that the path is a file
    >>> isfile( __file__ )
    True
    """
    state = os.path.isfile(path)
    if not state:
        msg = "file '%s' cannot be found" % path
        if verify:
            error(msg)
            raise IOError(msg)

    return state

def isdir( path, verify=True):
    """
    Verifies that the path is a directory
    >>> isdir(".")
    True
    """
    state = os.path.isdir(path)
    if not state:
        msg = "path '%s' is not a directory" % path
        if verify:
            error(msg)
            raise IOError(msg)
            
    return state

def testdata( fname, env=ENV, verify=True):
    """
    Returns the full path to a file in the test data directory
    >>> path = testdata( 'input-data.txt' )
    """
    isdir( env.TEST_DATA_DIR, verify=True )
    path = join_paths ( env.TEST_DATA_DIR, fname )
    isfile( path, verify=verify )
    return path

def homedata( fname, env=ENV, verify=True):
    """
    Used in testing returns the full path to a file in the home directory
    >>> path = testdata( 'input-data.txt' )
    """
    isdir( env.HOME_DIR, verify=True )
    path = join_paths ( env.HOME_DIR, fname )
    isfile( path, verify=verify )
    return path

def test( verbose=0 ):
    "Performs module level testing"
    import doctest
    doctest.testmod( optionflags=doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE, verbose=verbose )

if __name__ == "__main__":
    test()
